///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_MAT_C3DROTATION_H_
#define _BUOLA_MAT_C3DROTATION_H_

#include <buola/buola.h>

namespace buola { namespace mat {

///\addtogroup geometry
///@{

////////////////////////////////////////////////////////////////////////////

/// rotation in 3D

/// Represents a rotation in 3 dimensions, as yaw, pitch and roll angles.
/// This representation is quite intuitive, but it can't be directly used
/// to rotate vectors, so it has to be converted to a matrix or quaternion.
///
////////////////////////////////////////////////////////////////////////////

class C3DRotation
{
public:
//! \name constructor and destructor
//@{
    //! default constructor (leaves it uninitialized)
    C3DRotation()=default;

    //! copy constructor
    C3DRotation(const C3DRotation &pO)
        :   a(pO.a),
            b(pO.b),
            c(pO.c)
    {
    }

    //! from yaw, pitch and roll angles
    C3DRotation(double pa,double pb,double pc)
        :   a(pa),
            b(pb),
            c(pc)
    {
    }

    //! zero constructor
    explicit C3DRotation(NZero)
        :   a(0.0)
        ,   b(0.0)
        ,   c(0.0)
    {}

//@}

    //! assignment operator
    C3DRotation &operator=(const C3DRotation &pRH)=default;

    //! divides each angle by a scalar
    C3DRotation operator/(double pRH) const
    {
        return C3DRotation(a/pRH,b/pRH,c/pRH);
    }

    //! multiplies each angle by a scalar
    C3DRotation operator*(double pRH) const
    {
        return C3DRotation(a*pRH,b*pRH,c*pRH);
    }

    //! multiplies each angle by a scalar (in-place version)
    C3DRotation &operator*=(double pRH)
    {
        a*=pRH;
        b*=pRH;
        c*=pRH;

        return *this;
    }

    //! divides each angle by a scalar (in-place version)
    C3DRotation &operator/=(double pRH)
    {
        a/=pRH;
        b/=pRH;
        c/=pRH;

        return *this;
    }

    //! comparison operator

    //! \return true if the three angles are the same
    //! Two objects can represent the same rotation with the angles being
    //! different. In this case, this operator will still return false
    bool operator==(const C3DRotation &pRH) const
    {
        return (a==pRH.a&&b==pRH.b&&c==pRH.c);
    }

    //! inequality operator

    //! \return true if any of the three angles are different
    //! Two objects can represent the same rotation with the angles being
    //! different. In this case, this operator will still return true
    bool operator!=(const C3DRotation &pRH) const
    {
        return (a!=pRH.a||b!=pRH.b||c!=pRH.c);
    }

    double a;   //!< yaw
    double b;   //!< pitch
    double c;   //!< roll
};

//! negates the rotation
inline C3DRotation operator-(const C3DRotation &pRH)
{
    return C3DRotation(-pRH.a,-pRH.b,-pRH.c);
}

inline io::CTextWriter &operator<<(io::CTextWriter &pWriter,const C3DRotation &pRotation)
{
    pWriter << '(' << pRotation.a << ',' << pRotation.b << ',' << pRotation.c << ')';
    return pWriter;
}

inline io::CTextReader &operator>>(io::CTextReader &pReader,C3DRotation &pRotation)
{
    char lDummy;
    pReader >> lDummy >> pRotation.a >> lDummy >> pRotation.b >> lDummy >> pRotation.c >> lDummy;
    return pReader;
}

///converts from degrees to radians
inline C3DRotation deg2rad(const C3DRotation &pA)
{
    return pA*M_PI/180.0;
}

///converts from radians to degrees
inline C3DRotation rad2deg(const C3DRotation &pA)
{
    return pA*180.0/M_PI;
}

///@}

/*namespace mat*/ } /*namespace buola*/ }

#endif
